﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;

using zijian666.Converts.Abstractions;
using zijian666.Converts.Extensions;

namespace zijian666.Converts.Core;

/// <summary>
/// 转换上下文
/// </summary>
/// <remarks>
/// 构造函数
/// </remarks>
/// <param name="settings">转换设置</param>
public class ConvertContext(IConvertSettings? settings = null) : NameObjectCollectionBase, IConvertContext
{
    /// <summary>
    /// 当前线程的转换上下文对象
    /// </summary>
    [ThreadStatic]
    private static ConvertContext? _current;
    /// <summary>
    /// 当前线程的转换上下文对象
    /// </summary>
    public static ConvertContext? Current => _current;

    /// <summary>
    /// 转换设置
    /// </summary>
    public IConvertSettings Settings { get; } = settings ?? Converts.Settings;

    /// <summary>
    /// 当前对象是否已释放
    /// </summary>
    private bool _isdisposed;

    /// <summary>
    /// 上一个作用域的上下文对象
    /// </summary>
    private ConvertContext? _previous;

    /// <summary>
    /// 当前对象 this 是否是当前上下文 <seealso cref="Current"/>
    /// </summary>
    private bool IsCurrent() => ReferenceEquals(this, _current);

    /// <summary>
    /// 释放当前对象的占用资源
    /// </summary>
    /// <param name="disposing">是否释放托管资源</param>
    protected virtual void Dispose(bool disposing)
    {
        if (!_isdisposed)
        {
            if (disposing)
            {
                if (this.IsCurrent())
                {
                    _current = _previous;
                    _previous = null;
                }
            }
            _isdisposed = true;
        }
    }

    /// <summary>
    /// 释放当前对象
    /// </summary>
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }



    /// <summary>
    /// 创建转换上下文区域
    /// </summary>
    /// <param name="convertSettings">转换设置</param>
    /// <returns></returns>
    public static IConvertContext CreateScope(IConvertSettings? convertSettings)
    {
        if (_current is null)
        {
            return _current = new ConvertContext(convertSettings);
        }
        return _current.Scope(convertSettings, false);
    }

    /// <inheritdoc/>
    public IConvertContext Scope(IConvertSettings? settings, bool inherit)
    {
        if (inherit)
        {
            settings = settings.Merge(Settings);
        }

        if (this.IsCurrent())
        {
            return _current = new ConvertContext(settings) { _previous = this };
        }
        return new ConvertContext(settings) { _previous = this };
    }

    public object? this[string key]
    {
        get => BaseGet(key) ?? _previous?[key];
        set => BaseSet(key, value);
    }
}
